package com.group.project.hrms.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.group.project.hrms.entity.*;
import com.group.project.hrms.entity.ResultEntity.ResultEntity;
import com.group.project.hrms.entity.UsefulEntity.DateRangeEntity;
import com.group.project.hrms.entity.UsefulEntity.DayLeaveInfo;
import com.group.project.hrms.service.*;
import com.group.project.hrms.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Slf4j
@Controller
public class AttendanceMonthlyReportController {

    private static Logger logger = LoggerFactory.getLogger(AttendanceMonthlyReportController.class);

    @Autowired
    private IContactBasicService iContactBasicService;

    @Autowired
    private IContactBasicDeptInfoService basicDeptInfoService;

    @Autowired
    private IContactArchivesWorkingService archivesWorkingService;

    @Autowired
    private IDingClockRecordService iDingClockRecordService;

    @Autowired
    private IDingLeaveRecordService iDingLeaveRecordService;

    @Autowired
    private IDingVacationTypeService iDingVacationTypeService;

    @Autowired
    private IFrontLineVacationRecordService iFrontLineVacationRecordService;

    @Autowired
    private IFrontLineDayAdjustRecordService iFrontLineDayAdjustRecordService;

    @Autowired
    private IHolidayRecordService iHolidayRecordService;

    @Autowired
    private IAttendanceGroupInfoService iAttendanceGroupInfoService;

    @Autowired
    private IAttendanceShiftInfoService iAttendanceShiftInfoService;

    @Autowired
    private IOvertimeRulesService iOvertimeRulesService;

    @Autowired
    private ICheckPointInfoService iCheckPointInfoService;

    @Autowired
    private IRestTimeSettingsService iRestTimeSettingsService;

    @Autowired
    private ISpecialCheckDateService iSpecialCheckDateService;

    @Autowired
    private IAttendanceGroupDeptsService iAttendanceGroupDeptsService;

    @Autowired
    private IAttendanceGroupStaffsService iAttendanceGroupStaffsService;

    @Autowired
    private IAttendanceGroupStaffAdjustRecordService groupStaffAdjustRecordService;

    @Autowired
    private IAttendanceGroupDeptAdjustRecordService deptAdjustRecordService;

    @Autowired
    private IAttendanceMonthlyReportService iAttendanceMonthlyReportService;

    @Autowired
    private AttendanceUtil attendanceUtil;

    @Autowired
    private BasicInfoUtil basicInfoUtil;

    @Autowired
    private DateUtil dateUtil;

    @Autowired
    private ISalaryMonthlyReportService iSalaryMonthlyReportService;

    @Autowired
    private LogUtil logUtil;


    /**
     * 接收前端请求，计算月度考勤
     * @param map 需要计算的月份
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/basic/getAttendanceMonthlyReport")
    @ResponseBody
    public ResultEntity getAttendanceMonthlyReport(@RequestBody Map map, HttpServletRequest request){

        //获取请求中的在创建Token时注入的属性
        Object staffName = request.getAttribute("staffName");

        //创建操作时间对象
        Date currentDate = new Date();

        logger.info("基础信息开始加载，时间为：" + currentDate.toLocaleString());

        //创建结果集对象
        ResultEntity resultEntity = new ResultEntity();

        //用于存放服务器的返回结果
        List<Map> resultList = new ArrayList<>();

        //用于存储每个人的月度计算结果的Map
        Map<String, List> resultMap = new HashMap<>();

        //用于存储每个人的月度计算结果的List
        List<AttendanceMonthlyReport> reportList = new ArrayList<>();

        //用于存放每个人的所有dailyReportMap，即每个人在这个月每天的考勤计算结果
        Map<String, Map<Integer, AttendanceMonthlyReport>> totalDailyReportMaps = new HashMap<>();

        if(null != map){ //Map格式{monthDate=2022-01}

            Object month = map.get("monthDate");
            logger.info("即将计算的月份是：" + month);

            //判断传入的月份是否归档
            List<AttendanceMonthlyReport> archivedList = iAttendanceMonthlyReportService.selectAttendanceMonthlyReportByArchiveMonth(month.toString());
            if(archivedList.size() != 0){
                resultEntity.setCode("F");
                resultEntity.setMsg("该月份已经归档");
                //resultEntity.setDataList(reportList);
                return resultEntity;
            }

            //初始化归档缓存集合
            AttendanceUtil.reportList = new ArrayList<>();

            //加载基础数据------------------------------------------------------------------------------------

            //1,加载通讯录(含当月离职和入职人员)和部门列表
            logger.info("1,加载通讯录(含当月离职和入职人员)和部门列表");
            List<ContactBasic> contactBasics = iContactBasicService.selectAllContactBasicByStaffStatus(1);//所有在职人员信息 /// List
            if(null != contactBasics && contactBasics.size() == 0){
                resultEntity.setCode("F");
                resultEntity.setMsg("通讯录为空");
                resultEntity.setDataList(reportList);
                return resultEntity;
            }
            List<ContactArchivesWorking> leaveWorkingList = archivesWorkingService.selectContactArchivesWorkingsByLeaveMonth(month.toString());
            Map<String, ContactArchivesWorking> leaveWorkingListMap = new HashMap<>();
            if(null != leaveWorkingList && leaveWorkingList.size() != 0){
                for (ContactArchivesWorking working : leaveWorkingList
                     ) {
                    contactBasics.add(iContactBasicService.selectContactBasicByContactID(working.getContactId()));//将本月离职人员信息放入在职人员集合中
                }
                leaveWorkingListMap = attendanceUtil.getContactWorkingMap(leaveWorkingList);
            }
            List<ContactArchivesWorking> joinedWorkingList = archivesWorkingService.selectContactArchivesWorkingsByJoinedMonth(month.toString());
            Map<String, ContactArchivesWorking> joinedWorkingListMap = new HashMap<>();
            if(null != joinedWorkingList && joinedWorkingList.size() != 0){
                joinedWorkingListMap = attendanceUtil.getContactWorkingMap(joinedWorkingList);
            }

            logger.info("本月考勤参与的总人数：" + contactBasics.size() + " 人");
            logger.info("其中包含本月新入职人员：" + joinedWorkingList.size() + " 人，" + "本月离职人员：" + leaveWorkingList.size() + " 人");

            Map<String, String> deptsMap = basicInfoUtil.doGetDeptMap(basicDeptInfoService.selectAllContactBasicDeptInfo()); //加载部门信息 /// Map

            //将联系人和部门信息写入结果集Map
            resultMap.put("contacts", contactBasics);
            resultMap.put("depts", basicDeptInfoService.selectAllContactBasicDeptInfo());

            //2,加载打卡、请假等原始记录表信息
            logger.info("2,加载打卡、请假等原始记录表信息");

            List<DingClockRecord> dingClockRecords = iDingClockRecordService.selectDingClockRecordByDate(month.toString());
            logger.info("本月考勤打卡记录一共：" + dingClockRecords.size() + " 条");
            Map<String, List<DingClockRecord>> clocksMap = new HashMap<>();
            if(null != dingClockRecords && dingClockRecords.size() != 0){
                clocksMap = attendanceUtil.getDingClockRecordMap(dingClockRecords); //按照钉钉的userid为分组key，打卡对象集合为Value，形成 /// Map
            }

            List<DingLeaveRecord> leaveRecords = iDingLeaveRecordService.selectDingLeaveRecordByMonth(month.toString());
            Map<String, List<DingLeaveRecord>> leaveRecordsMap = new HashMap<>();
            if(null != leaveRecords){
                leaveRecordsMap = attendanceUtil.getDingLeaveRecordMap(leaveRecords); //按照钉钉的userid为分组key，请休假对象集合为Value，形成 /// Map
            }
            logger.info("本月办公人员考勤请休假记录一共：" + leaveRecords.size() + " 条");

            List<DingVacationType> vacationTypeList = iDingVacationTypeService.selectAllDingVacationType();
            Map<String, DingVacationType> vacationTypeMap = new HashMap<>();
            if(null != vacationTypeList){
                vacationTypeMap = attendanceUtil.getVacationTypeMap(vacationTypeList);
            }

            //3,加载当月节日记录计算并获取当月法定实际工作日集合、实际周末集合、实际节假日集合
            logger.info("3,加载当月节日记录计算并获取当月法定实际工作日集合、实际周末集合、实际节假日集合");
            List<HolidayRecord> holidayRecords = iHolidayRecordService.selectHolidayRecordByMonth(month.toString());  /// List
            logger.info("本月共有节假日和调休日：" + holidayRecords.size() + " 天");

            //加载当月计算所需的日期信息
            int maxDays; //初始化当月一共有多少天
            List<Integer> weekendList; //获取该月的周末日期集合 [5, 6, 12, 13, 19, 20, 26, 27]
            try{
                Calendar calendar = dateUtil.getCalendarByMonth(month.toString());
                maxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
                weekendList = dateUtil.getWeekendListByMonth(calendar);
            }catch (Exception e){
                e.printStackTrace();
                resultEntity.setCode("F");
                resultEntity.setMsg("程序在计算当月时间时出现异常");
                return resultEntity;
            }

            //计算并获取当月法定实际工作日集合、实际周末集合、实际节假日集合、实际调休日集合
            List<Integer> workingDays = new ArrayList<>();
            List<Integer> actualWeekends = new ArrayList<>();
            List<Integer> holidays = new ArrayList<>();
            for (int i = 1; i <= maxDays; i++) {
                if(1 == dateUtil.checkHoliday(holidayRecords, i)){ //这一天肯定是假日
                    holidays.add(i);
                }else if(2 == dateUtil.checkHoliday(holidayRecords, i)){ //这一天肯定是工作日调休
                    workingDays.add(i);
                }else if(3 == dateUtil.checkHoliday(holidayRecords, i)){ //这一天肯定是周末调休
                    actualWeekends.add(i);
                }else{ //在节假日中查询不到的，一定是工作日或者周末
                    if(dateUtil.isWeekend(weekendList, i)){
                        actualWeekends.add(i);
                    }else{
                        workingDays.add(i);
                    }
                }
            }
            logger.info("该月共有法定：" + workingDays.size() + " 天工作日，如下");
            logger.info(JSON.toJSONString(workingDays));
            logger.info("该月共有法定：" + actualWeekends.size() + " 天周末，如下");
            logger.info(JSON.toJSONString(actualWeekends));
            logger.info("该月共有法定：" + holidays.size() + " 天节假日，如下");
            logger.info(JSON.toJSONString(holidays));


            //获取当月第一天和最后一天的时间对象
            Date firstDate = dateUtil.formatStringToDate(month + "-01" + " 00:00:00");
            Date lastDate = dateUtil.formatStringToDate(month + "-" + maxDays + " 23:59:59");
            logger.info("该月第一天和最后一天的日期分别为：" + firstDate + " / " + lastDate);

            //计算当月应出勤小时数 - 当月的法定工作日乘以8小时 **********************
            float shouldAttendanceHours = workingDays.size() * 8; //仅用于无考勤组人员的应出勤，其它情况应该以考勤组的班次设置为准
            logger.info("该月应出勤总小时数为：" + shouldAttendanceHours);

            //4,加载一线生产录入系统所产生的数据(包含请假记录和额外加班动态调整记录)
            logger.info("4,加载一线生产录入系统所产生的数据(包含请假记录和额外加班动态调整记录)");
            List<FrontLineVacationRecord> frontLineVacationRecords = iFrontLineVacationRecordService.selectFrontLineVacationRecordByDateForOneContact(month.toString());
            Map<String, List<FrontLineVacationRecord>> frontLineVacationRecordsMap = new HashMap<>();
            if(null != frontLineVacationRecords){
                frontLineVacationRecordsMap = attendanceUtil.getFrontLineVacationRecordMap(frontLineVacationRecords); //按照通讯录ID为分组key，请休假对象集合为Value，形成 /// Map
            }
            List<FrontLineDayAdjustRecord> frontLineDayAdjustRecords = iFrontLineDayAdjustRecordService.selectFrontLineDayAdjustRecordByMonth(month.toString());
            Map<String, List<FrontLineDayAdjustRecord>> frontLineDayAdjustRecordsMap = new HashMap<>();
            if(null != frontLineDayAdjustRecords){
                frontLineDayAdjustRecordsMap = attendanceUtil.getFrontLineDayAdjustRecordMap(frontLineDayAdjustRecords); //按照通讯录ID为分组key，日动态调整对象集合为Value，形成 /// Map
            }
            logger.info("本月一线生产的请休假记录共计：" + frontLineVacationRecords.size() + " 条");
            logger.info("本月一线生产日加班动态调整记录共计：" + frontLineDayAdjustRecords.size() + " 条");


            //5,获取上月最后一天的打卡数据、请假记录、一线生产考勤系统产生的记录
            //logger.info("5,获取上月最后一天的打卡数据、请假记录、一线生产考勤系统产生的记录");
            //String lastMonthLastDay = dateUtil.dateToString(dateUtil.dateAddOne(firstDate, -1));
            //List<DingClockRecord> lastMonthLastDayClockRecords = iDingClockRecordService.selectDingClockRecordByDate(lastMonthLastDay);
            //Map<String, List<DingClockRecord>> lastMonthLastDayClocksMap = (null == lastMonthLastDayClockRecords || lastMonthLastDayClockRecords.size() == 0) ?  new HashMap<>() : attendanceUtil.getDingClockRecordMap(lastMonthLastDayClockRecords);
            //List<DingLeaveRecord> lastMonthLastDayLeaveRecords = iDingLeaveRecordService.selectDingLeaveRecordByMonth(lastMonthLastDay);
            //Map<String, List<DingLeaveRecord>> lastMonthLastDayLeaveRecordsMap = (null == lastMonthLastDayLeaveRecords || lastMonthLastDayLeaveRecords.size() == 0) ? new HashMap<>() : attendanceUtil.getDingLeaveRecordMap(lastMonthLastDayLeaveRecords);
            //List<FrontLineVacationRecord> lastMonthLastDayfrontLineVacationRecords = iFrontLineVacationRecordService.selectFrontLineVacationRecordByMonth(lastMonthLastDay);
            //Map<String, List<FrontLineVacationRecord>> lastMonthLastDayfrontLineVacationRecordsMap = (null == lastMonthLastDayfrontLineVacationRecords || lastMonthLastDayfrontLineVacationRecords.size() == 0) ? new HashMap<>() :attendanceUtil.getFrontLineVacationRecordMap(lastMonthLastDayfrontLineVacationRecords);
            //List<FrontLineDayAdjustRecord> lastMonthLastDayfrontLineDayAdjustRecords = iFrontLineDayAdjustRecordService.selectFrontLineDayAdjustRecordByMonth(lastMonthLastDay);
            //Map<String, List<FrontLineDayAdjustRecord>> lastMonthLastDayfrontLineDayAdjustRecordsMap = (null == lastMonthLastDayfrontLineDayAdjustRecords || lastMonthLastDayfrontLineDayAdjustRecords.size() == 0) ? new HashMap<>() : attendanceUtil.getFrontLineDayAdjustRecordMap(lastMonthLastDayfrontLineDayAdjustRecords);


            //5-1, 获取下月第一天的打卡记录、请假记录、一线生产考勤系统产生的记录
            logger.info("5-1, 获取下月第一天的打卡记录、请假记录、一线生产考勤系统产生的记录");
            String nextMonthFirstDay = dateUtil.dateToString(dateUtil.dateAddOne(lastDate, 1));
            List<DingClockRecord> nextMonthFirstDayClockRecords = iDingClockRecordService.selectDingClockRecordByDate(nextMonthFirstDay);
            Map<String, List<DingClockRecord>> nextMonthFirstDayClocksMap = (null == nextMonthFirstDayClockRecords || nextMonthFirstDayClockRecords.size() == 0) ?  new HashMap<>() : attendanceUtil.getDingClockRecordMap(nextMonthFirstDayClockRecords);
            List<DingLeaveRecord> nextMonthFirstDayLeaveRecords = iDingLeaveRecordService.selectDingLeaveRecordByMonth(nextMonthFirstDay);
            Map<String, List<DingLeaveRecord>> nextMonthFirstDayLeaveRecordsMap = (null == nextMonthFirstDayLeaveRecords || nextMonthFirstDayLeaveRecords.size() == 0) ? new HashMap<>() : attendanceUtil.getDingLeaveRecordMap(nextMonthFirstDayLeaveRecords);

            List<FrontLineVacationRecord> nextMonthFirstDayFrontLineVacationRecords = iFrontLineVacationRecordService.selectFrontLineVacationRecordByMonth(nextMonthFirstDay);
            Map<String, List<FrontLineVacationRecord>> nextMonthFirstDayFrontLineVacationRecordsMap = (null == nextMonthFirstDayFrontLineVacationRecords || nextMonthFirstDayFrontLineVacationRecords.size() == 0) ? new HashMap<>() :attendanceUtil.getFrontLineVacationRecordMap(nextMonthFirstDayFrontLineVacationRecords);

            //List<FrontLineDayAdjustRecord> nextMonthFirstDayFrontLineDayAdjustRecords = iFrontLineDayAdjustRecordService.selectFrontLineDayAdjustRecordByMonth(nextMonthFirstDay);
            //Map<String, List<FrontLineDayAdjustRecord>> nextMonthFirstDayFrontLineDayAdjustRecordsMap = (null == nextMonthFirstDayFrontLineDayAdjustRecords || nextMonthFirstDayFrontLineDayAdjustRecords.size() == 0) ? new HashMap<>() : attendanceUtil.getFrontLineDayAdjustRecordMap(nextMonthFirstDayFrontLineDayAdjustRecords);


            //6,加载考勤组设置数据
            logger.info("6,加载考勤组设置数据");
            List<AttendanceGroupInfo> groupInfos = iAttendanceGroupInfoService.selectAllAttendanceGroupInfo();
            List<CheckPointInfo> checkPointInfos = iCheckPointInfoService.selectAllCheckPointInfo();
            List<OvertimeRules> overtimeRules = iOvertimeRulesService.selectAllOvertimeRules();
            List<AttendanceShiftInfo> shiftInfos = iAttendanceShiftInfoService.selectAllAttendanceShiftInfo();
            List<RestTimeSettings> restTimeSettings = iRestTimeSettingsService.selectAllRestTimeSettings();
            List<SpecialCheckDate> specialCheckDates = iSpecialCheckDateService.selectAllSpecialCheckDate();

            Map<String, AttendanceGroupInfo> groupInfoMap = new HashMap<>();
            Map<String, CheckPointInfo> checkPointInfoMap = new HashMap<>();
            Map<String, OvertimeRules> overtimeRuleMap = new HashMap<>();
            Map<String, AttendanceShiftInfo> shiftInfoMap = new HashMap<>();
            Map<String, RestTimeSettings> restTimeSettingMap = new HashMap<>();
            Map<String, SpecialCheckDate> specialCheckDateMap = new HashMap<>();


            if(null != groupInfos && groupInfos.size() != 0){
                groupInfoMap = attendanceUtil.getAttendanceGroupInfoMap(groupInfos);
            }
            if(null != checkPointInfos && checkPointInfos.size() != 0){
                checkPointInfoMap = attendanceUtil.getCheckPointInfoMap(checkPointInfos);
            }
            if(null != overtimeRules && overtimeRules.size() != 0){
                overtimeRuleMap = attendanceUtil.getOvertimeRulesMap(overtimeRules);
            }
            if(null != shiftInfos && shiftInfos.size() != 0){
                shiftInfoMap = attendanceUtil.getAttendanceShiftInfoMap(shiftInfos);
            }
            if(null != restTimeSettings && restTimeSettings.size() != 0){
                restTimeSettingMap = attendanceUtil.getRestTimeSettingsMap(restTimeSettings);
            }
            if(null != specialCheckDates && specialCheckDates.size() != 0){
                specialCheckDateMap = attendanceUtil.getSpecialCheckDateMap(specialCheckDates);
            }

            List<AttendanceGroupDepts> groupDepts = iAttendanceGroupDeptsService.selectAllAttendanceGroupDepts();
            List<AttendanceGroupStaffs> groupStaffs = iAttendanceGroupStaffsService.selectAllAttendanceGroupStaffs();

            //获取当月考勤组调整记录
            List<AttendanceGroupStaffAdjustRecord> groupStaffAdjustRecords = groupStaffAdjustRecordService.selectAttendanceGroupStaffAdjustRecordByMonth(month.toString());
            Map<String, List<AttendanceGroupStaffAdjustRecord>> groupStaffAdjustRecordsMap = new HashMap<>();
            if(null != groupStaffAdjustRecords){
                groupStaffAdjustRecordsMap = attendanceUtil.getAttendanceGroupStaffAdjustRecordMap(groupStaffAdjustRecords);
            }

            Map<String, String> groupDeptMap = new HashMap<>();
            if(null != groupDepts){
                groupDeptMap = attendanceUtil.getGroupDeptMap(groupDepts);
            }
            Map<String, String> groupStaffMap = new HashMap<>();
            if(null != groupStaffs){
                groupStaffMap = attendanceUtil.getGroupStaffMap(groupStaffs);
            }

            List<AttendanceGroupDeptAdjustRecord> groupDeptAdjustRecords = deptAdjustRecordService.selectAttendanceGroupDeptAdjustRecordByMonth(month.toString());
            Map<Long, List<AttendanceGroupDeptAdjustRecord>> groupDeptAdjustRecordsMap = new HashMap<>(); //暂不支持追踪部门变更考勤组的记录
            if(null != groupDeptAdjustRecords){
                groupDeptAdjustRecordsMap = attendanceUtil.getAttendanceGroupDeptAdjustRecordMap(groupDeptAdjustRecords);
            }

            //获取下一个月考勤组调整记录
            List<AttendanceGroupStaffAdjustRecord> staffAdjustRecordsNextMonth = new ArrayList<>();
            try{
                staffAdjustRecordsNextMonth = groupStaffAdjustRecordService.selectAttendanceGroupStaffAdjustRecordByMonth(dateUtil.getNextMonthStrByDate(firstDate));
            }catch (Exception e){
                e.printStackTrace();
            }
            Map<String, List<AttendanceGroupStaffAdjustRecord>> staffAdjustRecordMapNextMonth = new HashMap<>();
            if(staffAdjustRecordsNextMonth.size() != 0){
                staffAdjustRecordMapNextMonth = attendanceUtil.getAttendanceGroupStaffAdjustRecordMap(staffAdjustRecordsNextMonth);
            }


            logger.info("基础信息记载并计算完毕，时间为：" + new Date().toLocaleString());
            logger.info("开始计算 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");


            //开始按每个人循环计算-按照通讯录循环（含当月离职人员）
            for (ContactBasic contactBasic : contactBasics
                 ) {
                //创建个人月度结果集对象，先计算每个人每日的报告，并将每日报告存入以日期为Key，日报告对象为Value的Map中，最后进行月度汇算
                AttendanceMonthlyReport userMonthlyReport = new AttendanceMonthlyReport(0F);
                userMonthlyReport.setReportId(UUIDUtil.createUUID());
                userMonthlyReport.setcTime(currentDate);

                Map<Integer, AttendanceMonthlyReport> dailyReportMap = new HashMap<>(); //创建DailyReport

                //处理个人打卡休假等信息
                List<DingClockRecord> userClockRecords = clocksMap.get(contactBasic.getDingUserid()); //钉钉打卡记录 - 需要非空判断
                Map<Integer, String> userClockMapGpByDayStr = new HashMap<>();
                if(null != userClockRecords){
                    Map<Integer, List<DingClockRecord>> userClockMapGpByDay = attendanceUtil.getDingClockRecordMapGrByDay(userClockRecords); //将个人打卡记录按天分组，便于查询
                    for (Map.Entry<Integer, List<DingClockRecord>> entry : userClockMapGpByDay.entrySet()){
                        userClockMapGpByDayStr.put(entry.getKey(), JSON.toJSONString(entry.getValue())); //将值转为String，目的是为了在get时不改变原值
                    }
                }

                List<DingLeaveRecord> userLeaveRecords = leaveRecordsMap.get(contactBasic.getDingUserid()); //钉钉请休假记录 - 限办公人员 - 需要非空判断
                Map<Integer, List<DingLeaveRecord>> userLeaveRecordMapGrByStart = new HashMap<>();
                Map<Integer, List<DingLeaveRecord>> userLeaveRecordMapGrByEnd = new HashMap<>();
                if(null != userLeaveRecords){
                    userLeaveRecordMapGrByStart = attendanceUtil.getDingLeaveRecordMapGrByStartTime(userLeaveRecords); //将个人休假记录按照开始时间的日期分组
                    userLeaveRecordMapGrByEnd = attendanceUtil.getDingLeaveRecordMapGrByEndTime(userLeaveRecords); //将个人休假记录按照结束时间的日期分组
                }

//                if(contactBasic.getContactId().equals("7bb49753b2")){
//                    System.out.println(JSON.toJSONString(userLeaveRecordMapGrByEnd.get(10)));
//                }

                List<FrontLineVacationRecord> frontVacationRecords = frontLineVacationRecordsMap.get(contactBasic.getContactId()); //一线人员请休假记录 - 需要非空判断
                Map<Integer, List<FrontLineVacationRecord>> userfrontVacationRecordMapGrByStart = new HashMap<>();
                Map<Integer, List<FrontLineVacationRecord>> userfrontVacationRecordMapGrByEnd = new HashMap<>();
                if(null != frontVacationRecords){
                    userfrontVacationRecordMapGrByStart = attendanceUtil.getFrontLineVacationRecordMapGrByStartTime(frontVacationRecords); //将一线人员请休假记录按照开始时间的日期分组
                    userfrontVacationRecordMapGrByEnd = attendanceUtil.getFrontLineVacationRecordMapGrByEndTime(frontVacationRecords); //将一线人员请休假记录按照开始时间的日期分组
                }
                List<FrontLineDayAdjustRecord> frontDayAdjustRecords = frontLineDayAdjustRecordsMap.get(contactBasic.getContactId()); //一线人员日动态调整的额外加班记录 - 需要非空判断
                Map<Integer, String> userFrontDayAdjustMapGrByDayStr = new HashMap<>();
                if(null != frontDayAdjustRecords){
                    Map<Integer, List<FrontLineDayAdjustRecord>> userFrontDayAdjustMapGrByDay = attendanceUtil.getFrontLineDayAdjustRecordMapGrByDay(frontDayAdjustRecords); //将一线人员日动态调整的额外加班记录按照日期分组
                    for (Map.Entry<Integer, List<FrontLineDayAdjustRecord>> entry : userFrontDayAdjustMapGrByDay.entrySet()){
                        userFrontDayAdjustMapGrByDayStr.put(entry.getKey(), JSON.toJSONString(entry.getValue())); //将值转为String，目的是为了在get时不改变原值
                    }
                }

                //获取该员工考勤组信息
                Long deptID = JSONArray.parseArray(contactBasic.getDept()).getLong(0);
                List<DateRangeEntity> rangeEntities = new ArrayList<>(); //创建用于将整月分阶段计算的日期段集合，其中包含有每个日期段所对应的考勤组ID
                if(null != groupStaffMap.get(contactBasic.getContactId())){

                    //当一个人员转移考勤组时，需要按转移时间将整月分段进行考勤计算。没有转移，则按整月计算。其中如果一个人的考勤组被删除而没有新增，则本月该人员都将无考勤组可使用
                    if(null != groupStaffAdjustRecordsMap.get(contactBasic.getContactId())){ //判断当前这个人是否存在异动
                        List<AttendanceGroupStaffAdjustRecord> sourceStaffAdjustRecords = groupStaffAdjustRecordsMap.get(contactBasic.getContactId());
                        List<AttendanceGroupStaffAdjustRecord> staffAdjustRecords = new ArrayList<>();
                        for (AttendanceGroupStaffAdjustRecord agar : sourceStaffAdjustRecords
                             ) {
                            if(agar.getAction() == 2){ //去除删除操作，将新增操作的记录单独筛选出来
                                staffAdjustRecords.add(agar);
                            }
                        }
                        //对人员异动记录按照新增操作的生效时间进行升序排列
                        Collections.sort(staffAdjustRecords, new Comparator<AttendanceGroupStaffAdjustRecord>() {
                            @Override
                            //定义一个比较器，按照生效日期升序排列
                            public int compare(AttendanceGroupStaffAdjustRecord d1, AttendanceGroupStaffAdjustRecord d2) {
                                try {
                                    Date dt1 = d1.getDateInForce();
                                    Date dt2 = d2.getDateInForce();
                                    if (dt1.getTime() > dt2.getTime()) {
                                        return 1;
                                    } else if (dt1.getTime() < dt2.getTime()) {
                                        return -1;
                                    } else {
                                        return 0;
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                return 0;
                            }
                        });

                        //对排列后的集合进行计算
                        for (int i = 0; i <= staffAdjustRecords.size(); i++) {
                            if(i == 0){
                                AttendanceGroupStaffAdjustRecord record = staffAdjustRecords.get(0);
                                int dateInt = record.getDateInForce().getDate();
                                DateRangeEntity dateRangeEntity = new DateRangeEntity();
                                dateRangeEntity.setStart(1);
                                dateRangeEntity.setEnd(dateInt - 1);
                                if(null != record.getPreviousGroupId()){
                                    dateRangeEntity.setAttendanceID(record.getPreviousGroupId());
                                }
                                rangeEntities.add(dateRangeEntity);
                            }
                            if(i == staffAdjustRecords.size()){
                                AttendanceGroupStaffAdjustRecord record = staffAdjustRecords.get(i - 1);
                                int dateInt = record.getDateInForce().getDate();
                                DateRangeEntity dateRangeEntity = new DateRangeEntity();
                                dateRangeEntity.setStart(dateInt);
                                dateRangeEntity.setEnd(maxDays);
                                dateRangeEntity.setAttendanceID(record.getAttendanceGroupId());
                                rangeEntities.add(dateRangeEntity);
                            }
                            if(i > 0 && i < staffAdjustRecords.size()){
                                AttendanceGroupStaffAdjustRecord record1 = staffAdjustRecords.get(i - 1);
                                AttendanceGroupStaffAdjustRecord record2 = staffAdjustRecords.get(i);
                                int dateInt1 = record1.getDateInForce().getDate();
                                int dateInt2 = record2.getDateInForce().getDate();
                                DateRangeEntity dateRangeEntity = new DateRangeEntity();
                                dateRangeEntity.setStart(dateInt1);
                                dateRangeEntity.setEnd(dateInt2 - 1);
                                if(null != record2.getPreviousGroupId()){
                                    dateRangeEntity.setAttendanceID(record2.getPreviousGroupId());
                                }else {
                                    dateRangeEntity.setAttendanceID(record2.getAttendanceGroupId());
                                }
                                rangeEntities.add(dateRangeEntity);
                            }
                        }
                    }else {
                        DateRangeEntity dateRangeEntity = new DateRangeEntity();
                        dateRangeEntity.setStart(1);
                        dateRangeEntity.setEnd(maxDays);
                        List<AttendanceGroupStaffAdjustRecord> nextMonthAdjustRecordList = staffAdjustRecordMapNextMonth.get(contactBasic.getContactId());
                        if(null != nextMonthAdjustRecordList && nextMonthAdjustRecordList.size() != 0){
                            AttendanceGroupStaffAdjustRecord record = null;
                            Iterator<AttendanceGroupStaffAdjustRecord> iterator = nextMonthAdjustRecordList.iterator();
                            while (iterator.hasNext()){
                                AttendanceGroupStaffAdjustRecord casualRecord = iterator.next();
                                if(null == record){
                                    record = casualRecord;
                                }else {
                                    if(record.getDateInForce().getTime() > casualRecord.getDateInForce().getTime()){
                                        record = casualRecord;
                                    }
                                }
                            }
                            if(null != record){
                                dateRangeEntity.setAttendanceID(record.getPreviousGroupId());
                            }
                        }else {
                            dateRangeEntity.setAttendanceID(groupStaffMap.get(contactBasic.getContactId()));
                        }
                        rangeEntities.add(dateRangeEntity);
                    }
                }

                //当一个部门转移考勤组时，目前仅支持整月生效，暂不支持分时间段生效
                if(null != groupDeptMap.get(deptID.toString())){
                    DateRangeEntity dateRangeEntity = new DateRangeEntity();
                    dateRangeEntity.setStart(1);
                    dateRangeEntity.setEnd(maxDays);
                    dateRangeEntity.setAttendanceID(groupDeptMap.get(deptID.toString()));
                    rangeEntities.add(dateRangeEntity);
                }

//                if(contactBasic.getContactId().equals("caaf4f8ff4")){
//                    System.out.println(JSON.toJSONString(rangeEntities));
//                }


                if(rangeEntities.size() != 0){
                    for (DateRangeEntity dre : rangeEntities
                    ) {
                        int start = dre.getStart();
                        int end = dre.getEnd();
                        String attendGroupID = dre.getAttendanceID();

                        //如果该员工所在的考勤组信息不为空，则开始根据考勤组规则开始计算其月度考勤数据
                        if(null != attendGroupID){

                            //获取当前人员计算月度考勤所需的信息 - 考勤组信息、打卡信息、请休假信息（其中生产人员的请休假及额外加班信息来自一线生产主管系统）
                            AttendanceGroupInfo groupInfo = groupInfoMap.get(attendGroupID); //考勤组信息
                            List<Integer> weekNumbersInGroup = new ArrayList<>(); //将考勤组中的工作日设置转化为1-7数组，原始ABCDEFG代表了周一到周日
                            if(groupInfo.getWorkingDay().contains("A")){ weekNumbersInGroup.add(1); }
                            if(groupInfo.getWorkingDay().contains("B")){ weekNumbersInGroup.add(2); }
                            if(groupInfo.getWorkingDay().contains("C")){ weekNumbersInGroup.add(3); }
                            if(groupInfo.getWorkingDay().contains("D")){ weekNumbersInGroup.add(4); }
                            if(groupInfo.getWorkingDay().contains("E")){ weekNumbersInGroup.add(5); }
                            if(groupInfo.getWorkingDay().contains("F")){ weekNumbersInGroup.add(6); }
                            if(groupInfo.getWorkingDay().contains("G")){ weekNumbersInGroup.add(7); }

                            //System.out.println("当前考勤组所包含的工作日如下：");
                            //System.out.println(weekNumbersInGroup);

                            String spCheckIDs = groupInfo.getSpecialCheckIds();
                            JSONArray jsonArray = JSONArray.parseArray(spCheckIDs);
                            List<Date> needList = new ArrayList<>(); //当前考勤组需要特殊打卡的日期
                            List<Date> notNeedList = new ArrayList<>(); //当前考勤组不需要特殊打卡的日期
                            if(null != jsonArray){
                                for (Object id : jsonArray
                                ) {
                                    SpecialCheckDate spd = specialCheckDateMap.get(id); //打卡标志，A为不打卡标志，表示该日期不需要打卡，B为打卡标志，表示该日期需要打卡
                                    if(spd.getCheckFlag().equals("A")){
                                        notNeedList.add(spd.getSpecialDate());
                                    }
                                    if(spd.getCheckFlag().equals("B")){
                                        needList.add(spd.getSpecialDate());
                                    }
                                }
                            }

                            AttendanceShiftInfo shiftInfo = shiftInfoMap.get(groupInfo.getAttendanceShiftId()); //班次信息
                            JSONArray restTimeIDs = shiftInfo.getRestTimeIds() == null ? null : JSONArray.parseArray(shiftInfo.getRestTimeIds());
                            OvertimeRules rules = overtimeRuleMap.get(groupInfo.getRulesId()); //加班规则，注意：普通办公人员的加班规则使用钉钉中的规则
                            //（原先处理个人打卡和休假信息在这里）




                            //按照考勤组变动的日期分段，循环计算每个人每一天考勤数据
                            for (int i = start; i <= end; i++) {

                                //对工作日、周末、节假日进行判断 - 以考勤组设置为准
                                String nowDay = i < 10 ? month.toString() + "-0" + i : month.toString() + "-" + i;
                                int weekInt = dateUtil.getWeekNumber(nowDay); //获取这一天是星期几

                                //创建每日考勤报告对象并初始化各项的值
                                AttendanceMonthlyReport dailyReport = new AttendanceMonthlyReport(0F); //使用带有初始化参数的构造器

                                //获取班次设置的上下班时间 - 其中包含将考勤设置中的打卡时间转为当天的打卡时间
                                Date onDutyTime = dateUtil.getDateByPointDate(nowDay, checkPointInfoMap.get(shiftInfo.getStartCheckPointId()).getStandardTime());
                                Date onDutyCheckStartTime = dateUtil.getDateByPointDate(nowDay, checkPointInfoMap.get(shiftInfo.getStartCheckPointId()).getStartTime());
                                Date onDutyCheckEndTime = dateUtil.getDateByPointDate(nowDay, checkPointInfoMap.get(shiftInfo.getStartCheckPointId()).getEndTime());

                                Date offDutyTime = dateUtil.getDateByPointDate(nowDay, checkPointInfoMap.get(shiftInfo.getEndCheckPointId()).getStandardTime());
                                Date offDutyCheckStartTime = dateUtil.getDateByPointDate(nowDay, checkPointInfoMap.get(shiftInfo.getEndCheckPointId()).getStartTime());
                                Date offDutyCheckEndTime = dateUtil.getDateByPointDate(nowDay, checkPointInfoMap.get(shiftInfo.getEndCheckPointId()).getEndTime());

                                boolean isNextDay = false; //跨夜考勤的情况 (已经改为向后一天取值)
                                if(onDutyTime.getTime() > offDutyTime.getTime()){
                                    isNextDay = true;
                                    //onDutyTime = dateUtil.dateAddOne(onDutyTime, -1);
                                    //onDutyCheckStartTime = dateUtil.dateAddOne(onDutyCheckStartTime, -1);
                                    //onDutyCheckEndTime = dateUtil.dateAddOne(onDutyCheckEndTime, -1);

                                    offDutyTime = dateUtil.dateAddOne(offDutyTime, 1);
                                    offDutyCheckStartTime = dateUtil.dateAddOne(offDutyCheckStartTime, 1);
                                    offDutyCheckEndTime = dateUtil.dateAddOne(offDutyCheckEndTime, 1);
                                }


                                //获取当日打卡记录
                                List<DingClockRecord> dayClockRecords = JSONArray.parseArray(userClockMapGpByDayStr.get(i), DingClockRecord.class);

                                //跨夜打卡记录 (向前跨夜取值)
//                                if(isNextDay && null != dayClockRecords){
//                                    List<DingClockRecord> lastMonthLastDayList = lastMonthLastDayClocksMap.get(contactBasic.getDingUserid());
//                                    if(i == 1 && null != lastMonthLastDayList){
//                                        dayClockRecords.addAll(lastMonthLastDayList);
//                                    }else {
//                                        List<DingClockRecord> lastDayList = JSONArray.parseArray(userClockMapGpByDayStr.get(i - 1), DingClockRecord.class);
//                                        if(null != lastDayList){
//                                            dayClockRecords.addAll(lastDayList);
//                                        }
//                                    }
//                                }

                                //向后跨夜取值
                                if(isNextDay && null != dayClockRecords){
                                    List<DingClockRecord> nextMonthFirstDayList = nextMonthFirstDayClocksMap.get(contactBasic.getDingUserid());
                                    if(i == maxDays && null != nextMonthFirstDayList){
                                        dayClockRecords.addAll(nextMonthFirstDayList);
                                    }else {
                                        List<DingClockRecord> nextDayList = JSONArray.parseArray(userClockMapGpByDayStr.get(i + 1), DingClockRecord.class);
                                        if(null != nextDayList){
                                            dayClockRecords.addAll(nextDayList);
                                        }
                                    }
                                }


//                                if(contactBasic.getContactId().equals("caaf4f8ff4")){
//                                    System.out.println(JSON.toJSONString(dayClockRecords));
//                                }


                                //跨夜个人请休假记录(来自钉钉和生产系统产生的记录)开始时间和结束时间都在这一天的记录合并并去重 (已经改为向后一天取值)
                                List<DingLeaveRecord> dayTotalLeaveRecords = attendanceUtil.getDayFinalLeaveRecords(userLeaveRecordMapGrByStart.get(i), userLeaveRecordMapGrByEnd.get(i));
                                if(isNextDay){
                                    if(i == maxDays && null != nextMonthFirstDayLeaveRecordsMap.get(contactBasic.getDingUserid())){
                                        List<DingLeaveRecord> casualLeaveList = nextMonthFirstDayLeaveRecordsMap.get(contactBasic.getDingUserid());
                                        dayTotalLeaveRecords = attendanceUtil.getDayFinalLeaveRecords(dayTotalLeaveRecords, attendanceUtil.getFinalLeaveRecords(casualLeaveList));
                                        //dayTotalLeaveRecords.addAll(attendanceUtil.getFinalLeaveRecords(casualLeaveList)); //去除集合中重复的请假 //该方式在夜班请假时会产生重复数据"$ref": "$[0]"
                                    }else {
                                        dayTotalLeaveRecords = attendanceUtil.getDayFinalLeaveRecords(dayTotalLeaveRecords, attendanceUtil.getDayFinalLeaveRecords(userLeaveRecordMapGrByStart.get(i + 1), userLeaveRecordMapGrByEnd.get(i + 1)));
                                        //dayTotalLeaveRecords.addAll(attendanceUtil.getDayFinalLeaveRecords(userLeaveRecordMapGrByStart.get(i + 1), userLeaveRecordMapGrByEnd.get(i + 1))); //该方式在夜班请假时会产生重复数据"$ref": "$[0]"
                                    }
                                }

                                List<FrontLineVacationRecord> dayTotalFrontLineLeaveRecords = attendanceUtil.getDayFinalFrontLineVacationRecords(userfrontVacationRecordMapGrByStart.get(i), userfrontVacationRecordMapGrByEnd.get(i));

//                                if(i == 7 && contactBasic.getContactId().equals("305dc24ee6")) {
//                                    System.out.println(JSON.toJSONString(dayTotalFrontLineLeaveRecords));
//                                }

                                if(isNextDay){
                                    List<FrontLineVacationRecord> casualList = nextMonthFirstDayFrontLineVacationRecordsMap.get(contactBasic.getContactId());
                                    if(i == maxDays && null != casualList){
                                        dayTotalFrontLineLeaveRecords = attendanceUtil.getDayFinalFrontLineVacationRecords(dayTotalFrontLineLeaveRecords, attendanceUtil.getFinalFrontLineVacationRecords(casualList));
                                        //dayTotalFrontLineLeaveRecords.addAll(attendanceUtil.getFinalFrontLineVacationRecords(casualList)); //去除集合中重复的请假 //该方式在夜班请假时会产生重复数据"$ref": "$[0]"
                                    }else {
                                        dayTotalFrontLineLeaveRecords = attendanceUtil.getDayFinalFrontLineVacationRecords(dayTotalFrontLineLeaveRecords, attendanceUtil.getDayFinalFrontLineVacationRecords(userfrontVacationRecordMapGrByStart.get(i + 1), userfrontVacationRecordMapGrByEnd.get(i + 1)));
                                        //dayTotalFrontLineLeaveRecords.addAll(attendanceUtil.getDayFinalFrontLineVacationRecords(userfrontVacationRecordMapGrByStart.get(i + 1), userfrontVacationRecordMapGrByEnd.get(i + 1))); //该方式在夜班请假时会产生重复数据"$ref": "$[0]"
                                    }
                                }





                                //跨夜一线生产系统产生的每天额外的加班时间
                                List<FrontLineDayAdjustRecord> dayAdjustRecords = JSONArray.parseArray(userFrontDayAdjustMapGrByDayStr.get(i), FrontLineDayAdjustRecord.class);


                                //检查计算当日请休假记录 - 判断如下四种情况，计算出这一天的休假总小时数
                                float casualLeaveHours = 0F; //当日事假
                                float medicalLeaveHours = 0F; //当日病假
                                float annualLeaveHours = 0F; //当日年假
                                float maternityLeaveHours = 0F; //当日产假
                                float marriageLeaveHours = 0F; //当日婚假
                                float bereavementLeaveHours = 0F; //当日丧假
                                float exchangeLeaveHours = 0F; //当日调休
                                float othersLeaveHours = 0F; //当日其它假
                                List leaveRecordList = null; //用于根据j来判断接收的对象，用于休假记录循环计算
                                List<Map<String, DayLeaveInfo>> recordMapList = new ArrayList<>(); //用于存储计算后的休假记录和计算后的休假时间
                                for (int j = 0; j < 2; j++) {
                                    if(j == 0){
                                        leaveRecordList = dayTotalLeaveRecords;
                                    }
                                    if(j == 1){
                                        leaveRecordList = dayTotalFrontLineLeaveRecords;
                                    }
                                    if(null != leaveRecordList && leaveRecordList.size() != 0){
                                        for (Object obj : leaveRecordList
                                        ) {
                                            String leaveCode;
                                            Date startTime;
                                            Date endTime;
                                            if(j == 0){
                                                DingLeaveRecord dlr = (DingLeaveRecord) obj;
                                                leaveCode = dlr.getLeaveCode();
                                                startTime = dlr.getStartTime();
                                                endTime = dlr.getEndTime();
                                            }else {
                                                FrontLineVacationRecord flvr = (FrontLineVacationRecord) obj;
                                                leaveCode = flvr.getVacationTypeCode();
                                                startTime = flvr.getStartTime();
                                                endTime = flvr.getEndTime();
                                            }

                                            Map<String, DayLeaveInfo> finalDingLeaveMap = attendanceUtil.getUserLeaveHours(leaveCode, startTime, endTime, onDutyTime, offDutyTime, restTimeIDs,
                                                    nowDay, restTimeSettingMap, vacationTypeMap, casualLeaveHours, medicalLeaveHours, annualLeaveHours, maternityLeaveHours,
                                                    marriageLeaveHours, bereavementLeaveHours, othersLeaveHours, exchangeLeaveHours, shiftInfo.getAutoDayworkHours());
                                            recordMapList.add(finalDingLeaveMap);//添加请休假详情，用于日常出勤的判断
                                            casualLeaveHours = finalDingLeaveMap.get("casualLeaveHours") == null ? casualLeaveHours : finalDingLeaveMap.get("casualLeaveHours").getCount();
                                            medicalLeaveHours = finalDingLeaveMap.get("medicalLeaveHours") == null ? medicalLeaveHours : finalDingLeaveMap.get("medicalLeaveHours").getCount();
                                            annualLeaveHours = finalDingLeaveMap.get("annualLeaveHours") == null ? annualLeaveHours : finalDingLeaveMap.get("annualLeaveHours").getCount();
                                            maternityLeaveHours = finalDingLeaveMap.get("maternityLeaveHours") == null ? maternityLeaveHours : finalDingLeaveMap.get("maternityLeaveHours").getCount();
                                            marriageLeaveHours = finalDingLeaveMap.get("marriageLeaveHours") == null ? marriageLeaveHours : finalDingLeaveMap.get("marriageLeaveHours").getCount();
                                            bereavementLeaveHours = finalDingLeaveMap.get("bereavementLeaveHours") == null ? bereavementLeaveHours : finalDingLeaveMap.get("bereavementLeaveHours").getCount();
                                            exchangeLeaveHours = finalDingLeaveMap.get("exchangeLeaveHours") == null ? exchangeLeaveHours : finalDingLeaveMap.get("exchangeLeaveHours").getCount();
                                            othersLeaveHours = finalDingLeaveMap.get("othersLeaveHours") == null ? othersLeaveHours : finalDingLeaveMap.get("othersLeaveHours").getCount();
                                        }
                                    }
                                }


                                //当日休假总小时数
                                float totalLeaveHours = casualLeaveHours + medicalLeaveHours + annualLeaveHours + maternityLeaveHours + marriageLeaveHours + bereavementLeaveHours + exchangeLeaveHours + othersLeaveHours;

//                                if(i == 7 && contactBasic.getContactId().equals("305dc24ee6")){
//                                    System.out.println(JSON.toJSONString(dayTotalFrontLineLeaveRecords));
//                                    //System.out.println(onDutyTime + " / " + offDutyTime);
//                                    System.out.println(contactBasic.getStaffName() + " 在 " + i + " 这一天的事假、病假、年假、产假、婚假、丧家、调休假和其它假分别为：" + dateUtil.getFloatWithTwoBit(casualLeaveHours) + " / " + dateUtil.getFloatWithTwoBit(medicalLeaveHours) + " / " + dateUtil.getFloatWithTwoBit(annualLeaveHours) + " / " + dateUtil.getFloatWithTwoBit(maternityLeaveHours) + " / " + dateUtil.getFloatWithTwoBit(marriageLeaveHours) + " / " + dateUtil.getFloatWithTwoBit(bereavementLeaveHours) + " / " + dateUtil.getFloatWithTwoBit(exchangeLeaveHours) + " / " + dateUtil.getFloatWithTwoBit(othersLeaveHours));
//                                }


                                //计算班次内考勤 和 计算加班考勤
                                float actualAttendanceHours = 0F;
                                long actualAttendanceMills = 0L;
                                int lateCount = 0; //迟到次数
                                int leaveEarlyCount = 0; //早退次数
                                int additionClockCount = 0; //补卡次数
                                int neglectWorkCount = 0; //旷工次数
                                float addAttendanceHours = 0F; //总加班时间


                                long totalShiftRestMills = 0L; //班次内休息时段时间总计(毫秒)
                                JSONArray shiftRestTimeIDs = (null == shiftInfo.getRestTimeIds()) ? null : JSONArray.parseArray(shiftInfo.getRestTimeIds());
                                if(null != shiftRestTimeIDs){
                                    for (Object id : shiftRestTimeIDs
                                    ) {
                                        totalShiftRestMills = totalShiftRestMills + (dateUtil.getDateByPointDate(nowDay, restTimeSettingMap.get(id).getEndTime()).getTime() - dateUtil.getDateByPointDate(nowDay, restTimeSettingMap.get(id).getStartTime()).getTime());
                                    }
                                }
                                float totalShiftRestHours = dateUtil.getHoursByMills(totalShiftRestMills); //班次内休息时段时间总计

                                long totalRuleRestMills = 0L; //加班规则内休息时段时间总计(毫秒)
                                JSONArray restTimeIDArray = (null == rules || rules.getRestTimeIds() == null) ? null : JSONArray.parseArray(rules.getRestTimeIds()); //班次内的休息时段IDs
                                if(null != restTimeIDArray){
                                    for (Object id : restTimeIDArray
                                    ) {
                                        totalRuleRestMills = totalRuleRestMills + (dateUtil.getDateByPointDate(nowDay, restTimeSettingMap.get(id).getEndTime()).getTime() - dateUtil.getDateByPointDate(nowDay, restTimeSettingMap.get(id).getStartTime()).getTime());
                                    }
                                }
                                float totalRuleRestHours = dateUtil.getHoursByMills(totalRuleRestMills); //加班规则内休息时段时间总计

                                //通过循环打卡时间，筛选出符合要求的打卡时间
                                Date onDutyCheck = null; //有效上班时间
                                Date lateCheck = null; //有效迟到时间
                                Date offDutyCheck = null; //有效下班时间
                                Date leaveEarlyCheck = null; //有效早退时间
                                Date midCheck = null; //在迟到和早退之前的打卡

                                Date firstDateInday = null; //查询当天第一次打卡，目的是为了计算周末和节假日不在正常考勤范围规则下的出勤时效
                                Date lastDataInDay = null; //查询当天最后一次打卡，目的是为了计算周末和节假日不在正常考勤范围规则下的出勤时效

                                if(null != dayClockRecords && dayClockRecords.size() != 0){
                                    for (DingClockRecord clock : dayClockRecords
                                    ) {
                                        //检查该打卡时间是否是补卡时间
                                        if(clock.getSourcetype().equals("APPROVE") && clock.getUserchecktime().getDate() == i){
                                            additionClockCount = additionClockCount + 1;
                                        }

                                        //检查上班打卡是否正常打卡、是否迟到, 检查下班打卡是否正常打卡、是否早退，其它情况属于旷工或存在请假
                                        Date userCheck = clock.getUserchecktime();
                                        long clockTime = userCheck.getTime();
                                        if(clockTime >= onDutyCheckStartTime.getTime() && clockTime <= onDutyTime.getTime() + shiftInfo.getMinLateHours() * 60 * 1000){ //正常上班打卡
                                            onDutyCheck = userCheck;
                                        }else if(clockTime > (onDutyTime.getTime() + shiftInfo.getMinLateHours() * 60 * 1000 ) && clockTime <= (onDutyTime.getTime() + shiftInfo.getMinNeglectWorkHours() * 60 * 1000 )){ //迟到
                                            lateCheck = userCheck;
                                        }else if(clockTime >= (offDutyCheckStartTime.getTime() - shiftInfo.getMinLeaveEarlyHours() * 60 * 1000) && clockTime <= offDutyCheckEndTime.getTime()){ //正常下班打卡
                                            if(null == offDutyCheck){
                                                offDutyCheck = userCheck;
                                            }else if(userCheck.getTime() > offDutyCheck.getTime()){
                                                offDutyCheck = userCheck;
                                            }
                                        }else if(clockTime < (offDutyTime.getTime() - shiftInfo.getMinLeaveEarlyHours() * 60 * 1000) && clockTime >= (offDutyTime.getTime() - shiftInfo.getMinNeglectWorkHours() * 60 * 1000)){ //早退
                                            leaveEarlyCheck = userCheck;
                                        }else if(clockTime > (onDutyTime.getTime() + shiftInfo.getMinNeglectWorkHours() * 60 * 1000 ) && clockTime < (offDutyTime.getTime() - shiftInfo.getMinNeglectWorkHours() * 60 * 1000)){
                                            if(null == midCheck){
                                                midCheck = userCheck;
                                            }else if(userCheck.getTime() > midCheck.getTime() && (null != onDutyCheck || null != lateCheck)){ //中间段打卡，当存在上班或迟到打卡时，取最大值（打卡最晚时间）
                                                midCheck = userCheck;
                                            }else if(userCheck.getTime() < midCheck.getTime()){ //中间段打卡，当存在下班或早退打卡时，取最小值（打卡最早时间）
                                                midCheck = userCheck;
                                            }
                                        }
                                        //获取每天第一次打卡和最后一次打卡
                                        if(null == firstDateInday){
                                            firstDateInday = userCheck;
                                        }
                                        if(null == lastDataInDay){
                                            lastDataInDay = userCheck;
                                        }
                                        if(null != firstDateInday){
                                            if(userCheck.getTime() < firstDateInday.getTime()){ //寻找一天中的打卡最小值
                                                firstDateInday = userCheck;
                                            }
                                        }
                                        if(null != lastDataInDay){
                                            if(userCheck.getTime() > lastDataInDay.getTime()){ //寻找一天中的打卡最大值
                                                lastDataInDay = userCheck;
                                            }
                                        }
                                    }
                                    if(null != onDutyCheck){ //在上班存在有效时间时，迟到时间即使能获取，也应该设置为null
                                        lateCheck = null;
                                    }
                                    if(null != offDutyCheck){ //在下班存在有效时间时，早退时间即使能获取，同样应该设置为null
                                        leaveEarlyCheck = null;
                                    }
                                }



                                //计算加班时间
                                if(null != rules){ //存在加班规则的情况下再计算加班时间
                                    int isApprove = rules.getIsMustApprove(); //加班是否需要审批，1表示不需要，0表示需要
                                    float minMins = rules.getMinOvertimeHours(); //最小加班时间，分钟
                                    float maxMins = rules.getMaxOvertimeHours(); //最大加班时间，分钟
                                    float unit = rules.getOvertimeUnit(); //加班步进值，分钟
                                    int method = rules.getRoundingMethod(); //取整方式，1表示向下取整，2表示向上取整
                                    if(null != offDutyCheck && (null != onDutyCheck || null != lateCheck || null != midCheck)){
                                        long addTotalMills = offDutyCheck.getTime() - offDutyTime.getTime(); //获取未去除加班时间内的休息时段的总加班毫秒数

                                        //循环判断下班后的打卡时间是否包含了加班规则内的休息时段
                                        JSONArray restInRuleIDs = (null == rules || rules.getRestTimeIds() == null) ? null : JSONArray.parseArray(rules.getRestTimeIds()); //班次内的休息时段IDs
                                        if(null != restInRuleIDs){
                                            for (Object id : restInRuleIDs
                                            ) {
                                                Date ruleRestStart = dateUtil.getDateByPointDate(nowDay, restTimeSettingMap.get(id).getStartTime());
                                                Date ruleRestEnd = dateUtil.getDateByPointDate(nowDay, restTimeSettingMap.get(id).getEndTime());
                                                if(offDutyCheck.getTime() > ruleRestStart.getTime()){
                                                    addTotalMills = addTotalMills - (ruleRestEnd.getTime() - ruleRestStart.getTime()); //若下班后的加班打卡时间超过了加班规则中约定的休息时间的开始时间点，则加班时间毫秒数会减去此休息时段的毫秒数
                                                }
                                            }
                                        }

                                        float addTotalMins = dateUtil.getHoursByMills(addTotalMills) * 60; //总的加班分钟数
                                        if(addTotalMins >= minMins && addTotalMins <= maxMins){ //如果加班时间在允许的最大值和最小值之间，则按照取整方式进行计算
                                            if(isApprove == 1){ //不需要审批
                                                if(addTotalMins < unit){
                                                    addAttendanceHours = (method == 2) ? 0 : unit / 60 ;
                                                }else if(addTotalMins >= unit && addTotalMins % unit == 0){
                                                    addAttendanceHours = addTotalMins / 60 ;
                                                }else {
                                                    addAttendanceHours = (method == 2) ? ((int)(addTotalMins / unit) * unit) / 60 : (((int)(addTotalMins / unit) + 1) * unit) / 60 ;
                                                }
                                            }else{
                                                //需要审批，暂不处理，后续开发，如果是，则获取加班申请单据详情进行计算

                                            }
                                        }else if(addTotalMins > maxMins){ //如果加班时间大于最大允许的加班分钟数，则加班时间为加班允许的最大值
                                            if(isApprove == 1){
                                                addAttendanceHours = dateUtil.getFloatWithOneBit(maxMins / 60 );
                                            }else{
                                                //需要审批，暂不处理，后续开发，如果是，则获取加班申请单据详情进行计算
                                            }
                                        }
                                    }
                                }


                                //根据有效打卡时间、请休假记录及休息时段计算实际当日出勤时间
                                if(null != onDutyCheck && null != offDutyCheck){ //正常出勤
                                    actualAttendanceHours = dateUtil.getHoursByMills(offDutyTime.getTime() - onDutyTime.getTime() - totalShiftRestMills) - totalLeaveHours;
                                }else if((null == onDutyCheck && null != offDutyCheck) || (null != onDutyCheck && null == offDutyCheck)){ //存在迟到、早退、请假或者旷工
                                    if(null != lateCheck && null != offDutyCheck){
                                        if(recordMapList.size() != 0){
                                            if(!attendanceUtil.checkTimeInLeaveRecords(recordMapList, lateCheck)){
                                                actualAttendanceHours = dateUtil.getHoursByMills(offDutyTime.getTime() - onDutyTime.getTime() - totalShiftRestMills) - totalLeaveHours;
                                                lateCount = 1;
                                            }else {
                                                actualAttendanceHours = dateUtil.getHoursByMills(offDutyTime.getTime() - lateCheck.getTime() - totalShiftRestMills);
                                            }
                                        }else {
                                            actualAttendanceHours = dateUtil.getHoursByMills(offDutyTime.getTime() - onDutyTime.getTime() - totalShiftRestMills ) - totalLeaveHours;
                                            lateCount = 1;
                                        }
                                    }else if(null != onDutyCheck && null != leaveEarlyCheck){
                                        if(recordMapList.size() != 0){
                                            if(!attendanceUtil.checkTimeInLeaveRecords(recordMapList, leaveEarlyCheck)){
                                                actualAttendanceHours = dateUtil.getHoursByMills(offDutyTime.getTime() - onDutyTime.getTime() - totalShiftRestMills ) - totalLeaveHours;
                                                leaveEarlyCount = 1;
                                            }else {
                                                actualAttendanceHours = dateUtil.getHoursByMills(leaveEarlyCheck.getTime() - onDutyTime.getTime() - totalShiftRestMills );
                                            }
                                        }else {
                                            actualAttendanceHours = dateUtil.getHoursByMills(offDutyTime.getTime() - onDutyTime.getTime() - totalShiftRestMills ) - totalLeaveHours;
                                            leaveEarlyCount = 1;
                                        }
                                    }else {
                                        if(null != midCheck){

                                            if(null != onDutyCheck){
                                                //actualAttendanceHours = dateUtil.getHoursByMills(midCheck.getTime() - onDutyTime.getTime() - totalShiftRestMills);
                                                actualAttendanceMills = midCheck.getTime() - onDutyTime.getTime();
                                            }
                                            if(null != offDutyCheck){
                                                //actualAttendanceHours = dateUtil.getHoursByMills(offDutyTime.getTime() - midCheck.getTime() - totalShiftRestMills);
                                                actualAttendanceMills = offDutyTime.getTime() - midCheck.getTime();
                                            }
                                            if(null != shiftRestTimeIDs){
                                                for (Object id : shiftRestTimeIDs
                                                ) {
                                                    Date restStartTime = dateUtil.getDateByPointDate(nowDay, restTimeSettingMap.get(id).getStartTime());
                                                    Date restEndTime = dateUtil.getDateByPointDate(nowDay, restTimeSettingMap.get(id).getEndTime());

                                                    if(isNextDay){
                                                        int onDutyHour = dateUtil.getHourByDate(onDutyTime);
                                                        int onRestStartHour = dateUtil.getHourByDate(restStartTime);
                                                        if(onRestStartHour > onDutyHour && onRestStartHour <= 23){
                                                            restStartTime = dateUtil.dateAddOne(restStartTime, -1);
                                                            restEndTime = dateUtil.dateAddOne(restEndTime, -1);
                                                        }
                                                    }

                                                    if((null != offDutyCheck && midCheck.getTime() <= restStartTime.getTime()) || (null != onDutyCheck && midCheck.getTime() >= restEndTime.getTime())){
                                                        actualAttendanceMills = actualAttendanceMills - (restEndTime.getTime() - restStartTime.getTime());
                                                    }
                                                }
                                            }
                                            actualAttendanceHours = dateUtil.getHoursByMills(actualAttendanceMills);

                                            if(recordMapList.size() != 0){
                                                if(attendanceUtil.checkTimeInLeaveRecords(recordMapList, midCheck)){
                                                    //存在请假的情况，不作为旷工处理，否则按旷工计
                                                }else{
                                                    neglectWorkCount = 1;
                                                }
                                            }else {
                                                neglectWorkCount = 1;
                                            }
                                        }else {
                                            neglectWorkCount = 1;
                                        }
                                    }
                                }else{
                                    if(null != lateCheck && null != leaveEarlyCheck){
                                        //actualAttendanceHours = dateUtil.getHoursByMills(leaveEarlyCheck.getTime() - lateCheck.getTime() - totalShiftRestMills ) - totalLeaveHours;
                                        if(recordMapList.size() != 0){
                                            if(!attendanceUtil.checkTimeInLeaveRecords(recordMapList, lateCheck)){
                                                lateCount = 1;
                                            }
                                            if(!attendanceUtil.checkTimeInLeaveRecords(recordMapList, leaveEarlyCheck)){
                                                leaveEarlyCount = 1;
                                            }
                                            if(lateCount == 0 && leaveEarlyCount == 0){
                                                actualAttendanceHours = dateUtil.getHoursByMills(leaveEarlyCheck.getTime() - lateCheck.getTime() - totalShiftRestMills ) - totalLeaveHours;
                                            }
                                        }else {
                                            actualAttendanceHours = dateUtil.getHoursByMills(leaveEarlyCheck.getTime() - lateCheck.getTime() - totalShiftRestMills);
                                            lateCount = 1;
                                            leaveEarlyCount = 1;
                                        }
                                    }else {
                                        if(null != midCheck){

                                            if(null != lateCheck){
                                                //actualAttendanceHours = dateUtil.getHoursByMills(midCheck.getTime() - lateCheck.getTime() - totalShiftRestMills );
                                                actualAttendanceMills = midCheck.getTime() - lateCheck.getTime();
                                                lateCount = 1;
                                            }
                                            if(null != leaveEarlyCheck){
                                                //actualAttendanceHours = dateUtil.getHoursByMills(leaveEarlyCheck.getTime() - midCheck.getTime() - totalShiftRestMills );
                                                actualAttendanceMills = leaveEarlyCheck.getTime() - midCheck.getTime();
                                                leaveEarlyCount = 1;
                                            }
                                            if(null != shiftRestTimeIDs){
                                                for (Object id : shiftRestTimeIDs
                                                ) {
                                                    Date restStartTime = dateUtil.getDateByPointDate(nowDay, restTimeSettingMap.get(id).getStartTime());
                                                    Date restEndTime = dateUtil.getDateByPointDate(nowDay, restTimeSettingMap.get(id).getEndTime());

                                                    if(isNextDay){
                                                        int onDutyHour = dateUtil.getHourByDate(onDutyTime);
                                                        int onRestStartHour = dateUtil.getHourByDate(restStartTime);
                                                        if(onRestStartHour > onDutyHour && onRestStartHour <= 23){
                                                            restStartTime = dateUtil.dateAddOne(restStartTime, -1);
                                                            restEndTime = dateUtil.dateAddOne(restEndTime, -1);
                                                        }
                                                    }

                                                    if((null != leaveEarlyCheck && midCheck.getTime() <= restStartTime.getTime()) || (null != lateCheck && midCheck.getTime() >= restEndTime.getTime())){
                                                        actualAttendanceMills = actualAttendanceMills - (restEndTime.getTime() - restStartTime.getTime());
                                                    }
                                                }
                                            }
                                            actualAttendanceHours = dateUtil.getHoursByMills(actualAttendanceMills);

                                            if(recordMapList.size() != 0){
                                                if(attendanceUtil.checkTimeInLeaveRecords(recordMapList, midCheck)){
                                                    //存在请假的情况，不作为旷工处理，否则按旷工计
                                                }else{
                                                    neglectWorkCount = 1;
                                                }
                                            }else {
                                                neglectWorkCount = 1;
                                            }
                                        }else {
                                            neglectWorkCount = 1;
                                        }
                                    }
                                }

                                //根据每日最早打卡时间和最晚打卡时间计算出
                                float baseDiffHoursInDay = 0F;
                                if(null != firstDateInday && null != lastDataInDay && null != rules){
                                    baseDiffHoursInDay = dateUtil.getHoursByMills(lastDataInDay.getTime() - firstDateInday.getTime());
                                    //做向上取整0.5操作
                                    baseDiffHoursInDay = attendanceUtil.doRoundingUp(baseDiffHoursInDay);
                                }

                                //如果日休假时间到达了班次内的应出勤小时数，则将矿工置为0次
                                if(totalLeaveHours == shiftInfo.getAutoDayworkHours() || totalLeaveHours > shiftInfo.getAutoDayworkHours()){
                                    neglectWorkCount = 0;
                                }

                                //对日报告中的实际出勤做向上取整0.5操作
                                actualAttendanceHours = attendanceUtil.doRoundingUp(actualAttendanceHours);

                                //将上下班的标准时间和有效打卡时间存入日报表
                                dailyReport.setOnDutyTime(onDutyTime);
                                dailyReport.setOffDutyTime(offDutyTime);
                                if(null != onDutyCheck){
                                    dailyReport.setOnDutyCheckTime(onDutyCheck);
                                }
                                if(null != lateCheck){
                                    dailyReport.setLateCheckTime(lateCheck);
                                }
                                if(null != offDutyCheck){
                                    dailyReport.setOffDutyCheckTime(offDutyCheck);
                                }
                                if(null != leaveEarlyCheck){
                                    dailyReport.setEarlyCheckTime(leaveEarlyCheck);
                                }


                                //计算一线生产主管额外的加班
                                float frontExtAddAttendanceHours = 0F;
                                if(null != dayAdjustRecords && dayAdjustRecords.size() != 0){
                                    for (FrontLineDayAdjustRecord dayAdjustRecord : dayAdjustRecords
                                         ) {
                                        frontExtAddAttendanceHours = frontExtAddAttendanceHours + dayAdjustRecord.getAdjustHours();
                                    }
                                }

//                                if(contactBasic.getContactId().equals("eba24a1534")){
//                                    if(i == 3){
//                                        System.out.println("张书启在 " + i + " 这一天的数据为：" + "实际出勤：" + actualAttendanceHours + " 实际加班：" + addAttendanceHours + " 额外加班：" + frontExtAddAttendanceHours);
//                                    }
//                                }

                                //考勤组类别，0表示是计件考勤组，1表示计时临时工，2表示全勤一线考勤组，3表示全勤办公考勤组，4表示默认考勤组，默认全勤
                                if(groupInfo.getAttendanceType() == 1){ //计件和临时计时工需要单独计算 - 不区分法定假日和周末 - 参考加班规则但将加班时间计入应出勤（同实际出勤）
                                    dailyReport.setShouldAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                    dailyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));

                                    dailyReport.setCasualLeaveHours(dateUtil.getFloatWithOneBit(casualLeaveHours));
                                    dailyReport.setMedicalLeaveHours(dateUtil.getFloatWithOneBit(medicalLeaveHours));
                                    dailyReport.setAnnualLeaveHours(dateUtil.getFloatWithOneBit(annualLeaveHours));
                                    dailyReport.setMaternityLeaveHours(dateUtil.getFloatWithOneBit(maternityLeaveHours));
                                    dailyReport.setMarriageLeaveHours(dateUtil.getFloatWithOneBit(marriageLeaveHours));
                                    dailyReport.setBereavementLeaveHours(dateUtil.getFloatWithOneBit(bereavementLeaveHours));
                                    dailyReport.setExchangeLeaveHours(dateUtil.getFloatWithOneBit(exchangeLeaveHours));
                                    dailyReport.setOthersLeaveHours(dateUtil.getFloatWithOneBit(othersLeaveHours));

                                    dailyReport.setLateCount(lateCount);
                                    dailyReport.setLeaveEarlyCount(leaveEarlyCount);
                                    dailyReport.setAdditionClockCount(additionClockCount);
                                    dailyReport.setNeglectWorkCount(neglectWorkCount);

                                    dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));

                                }
                                if(groupInfo.getAttendanceType() == 0 || groupInfo.getAttendanceType() == 2 || groupInfo.getAttendanceType() == 3){
                                    //判断这一天是否是特殊日期
                                    if(dateUtil.isContactDate(nowDay, needList)){
                                        //这一天是特殊打卡日，将按照工作日计算出勤和加班
                                        dailyReport.setShouldAttendanceHours(0F);
                                        dailyReport.setActualAttendanceHours(0F);
                                        dailyReport.setSpecialDayAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours));

                                        dailyReport.setCasualLeaveHours(dateUtil.getFloatWithOneBit(casualLeaveHours));
                                        dailyReport.setMedicalLeaveHours(dateUtil.getFloatWithOneBit(medicalLeaveHours));
                                        dailyReport.setAnnualLeaveHours(dateUtil.getFloatWithOneBit(annualLeaveHours));
                                        dailyReport.setMaternityLeaveHours(dateUtil.getFloatWithOneBit(maternityLeaveHours));
                                        dailyReport.setMarriageLeaveHours(dateUtil.getFloatWithOneBit(marriageLeaveHours));
                                        dailyReport.setBereavementLeaveHours(dateUtil.getFloatWithOneBit(bereavementLeaveHours));
                                        dailyReport.setExchangeLeaveHours(dateUtil.getFloatWithOneBit(exchangeLeaveHours));
                                        dailyReport.setOthersLeaveHours(dateUtil.getFloatWithOneBit(othersLeaveHours));

                                        dailyReport.setDailyOvertimeHours(dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));

                                        dailyReport.setLateCount(lateCount);
                                        dailyReport.setLeaveEarlyCount(leaveEarlyCount);
                                        dailyReport.setAdditionClockCount(additionClockCount);
                                        dailyReport.setNeglectWorkCount(neglectWorkCount);

                                        dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));

                                        dailyReport.setDayType("A");

                                    }else if(dateUtil.isContactDate(nowDay, notNeedList)){
                                        //这一天是特殊不打卡日，将按照工作日只计算加班
                                        if(null != rules){
                                            //dailyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours));
                                            dailyReport.setDailyOvertimeHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                            dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                        }
                                        dailyReport.setDayType("B");
                                    }else{
                                        if(groupInfo.getIsContainHoliday() == 1){ //工作日是否包含节假日，1表示不包含
                                            if(holidays.contains(i)){ //是否是法定节假日
                                                //按照法定节假日计算加班
                                                if(null != rules){
                                                    dailyReport.setAdditionClockCount(additionClockCount);
                                                    //dailyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours));
                                                    dailyReport.setHolidayOvertimeHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                                    dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                                }
                                                dailyReport.setDayType("E");
                                            }else if(actualWeekends.contains(i)){ //是否是法定周末
                                                //按照周末计算加班
                                                if(null != rules){
                                                    dailyReport.setAdditionClockCount(additionClockCount);
                                                    //dailyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours));
                                                    dailyReport.setWeekendOvertimeHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                                    dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                                }
                                                dailyReport.setDayType("D");
                                            }else if(workingDays.contains(i)){ //法定工作日中是否包含这一天
                                                if(2 == dateUtil.checkHoliday(holidayRecords, i)){
                                                    //按照工作日计算正常考勤和加班
                                                    dailyReport.setShouldAttendanceHours(shiftInfo.getAutoDayworkHours());
                                                    dailyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours));

                                                    dailyReport.setCasualLeaveHours(dateUtil.getFloatWithOneBit(casualLeaveHours));
                                                    dailyReport.setMedicalLeaveHours(dateUtil.getFloatWithOneBit(medicalLeaveHours));
                                                    dailyReport.setAnnualLeaveHours(dateUtil.getFloatWithOneBit(annualLeaveHours));
                                                    dailyReport.setMaternityLeaveHours(dateUtil.getFloatWithOneBit(maternityLeaveHours));
                                                    dailyReport.setMarriageLeaveHours(dateUtil.getFloatWithOneBit(marriageLeaveHours));
                                                    dailyReport.setBereavementLeaveHours(dateUtil.getFloatWithOneBit(bereavementLeaveHours));
                                                    dailyReport.setExchangeLeaveHours(dateUtil.getFloatWithOneBit(exchangeLeaveHours));
                                                    dailyReport.setOthersLeaveHours(dateUtil.getFloatWithOneBit(othersLeaveHours));

                                                    dailyReport.setDailyOvertimeHours(dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));

                                                    dailyReport.setLateCount(lateCount);
                                                    dailyReport.setLeaveEarlyCount(leaveEarlyCount);
                                                    dailyReport.setAdditionClockCount(additionClockCount);
                                                    dailyReport.setNeglectWorkCount(neglectWorkCount);

                                                    dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));

                                                    dailyReport.setDayType("C");
                                                }else {
                                                    if(weekNumbersInGroup.contains(weekInt)){ //判断考勤组设置中是否包含这一天，不包含就算工作日加班
                                                        //按照工作日计算正常考勤和加班
                                                        dailyReport.setShouldAttendanceHours(shiftInfo.getAutoDayworkHours());
                                                        dailyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours));

                                                        dailyReport.setCasualLeaveHours(dateUtil.getFloatWithOneBit(casualLeaveHours));
                                                        dailyReport.setMedicalLeaveHours(dateUtil.getFloatWithOneBit(medicalLeaveHours));
                                                        dailyReport.setAnnualLeaveHours(dateUtil.getFloatWithOneBit(annualLeaveHours));
                                                        dailyReport.setMaternityLeaveHours(dateUtil.getFloatWithOneBit(maternityLeaveHours));
                                                        dailyReport.setMarriageLeaveHours(dateUtil.getFloatWithOneBit(marriageLeaveHours));
                                                        dailyReport.setBereavementLeaveHours(dateUtil.getFloatWithOneBit(bereavementLeaveHours));
                                                        dailyReport.setExchangeLeaveHours(dateUtil.getFloatWithOneBit(exchangeLeaveHours));
                                                        dailyReport.setOthersLeaveHours(dateUtil.getFloatWithOneBit(othersLeaveHours));

                                                        dailyReport.setDailyOvertimeHours(dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));

                                                        dailyReport.setLateCount(lateCount);
                                                        dailyReport.setLeaveEarlyCount(leaveEarlyCount);
                                                        dailyReport.setAdditionClockCount(additionClockCount);
                                                        dailyReport.setNeglectWorkCount(neglectWorkCount);

                                                        dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));

                                                        dailyReport.setDayType("C");

                                                    }else {
                                                        //按工作日只计算加班
                                                        if(null != rules){
                                                            dailyReport.setAdditionClockCount(additionClockCount);
                                                            //dailyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours));
                                                            dailyReport.setDailyOvertimeHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                                            dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                                        }
                                                        dailyReport.setDayType("B");
                                                    }
                                                }
                                            }
                                        }
                                        if(groupInfo.getIsContainHoliday() == 0){ //工作日是否包含节假日，0表示包含
                                            if(weekendList.contains(i)){ //weekendList为实际月份中的周末（忽略了节假日的存在）
                                                //这一天按照法定周末只计算加班
                                                if(null != rules){
                                                    dailyReport.setAdditionClockCount(additionClockCount);
                                                    //dailyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours));
                                                    dailyReport.setWeekendOvertimeHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                                    dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                                }
                                                dailyReport.setDayType("D");
                                            }else{ //除了周末，即工作日
                                                if(weekNumbersInGroup.contains(weekInt)){ //如果考勤组中工作日设置包含了这一天，则该日为工作日，weekInt表示周几
                                                    //这一天将按照工作日计算考勤和加班
                                                    dailyReport.setShouldAttendanceHours(shiftInfo.getAutoDayworkHours());
                                                    dailyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours));

                                                    dailyReport.setCasualLeaveHours(dateUtil.getFloatWithOneBit(casualLeaveHours));
                                                    dailyReport.setMedicalLeaveHours(dateUtil.getFloatWithOneBit(medicalLeaveHours));
                                                    dailyReport.setAnnualLeaveHours(dateUtil.getFloatWithOneBit(annualLeaveHours));
                                                    dailyReport.setMaternityLeaveHours(dateUtil.getFloatWithOneBit(maternityLeaveHours));
                                                    dailyReport.setMarriageLeaveHours(dateUtil.getFloatWithOneBit(marriageLeaveHours));
                                                    dailyReport.setBereavementLeaveHours(dateUtil.getFloatWithOneBit(bereavementLeaveHours));
                                                    dailyReport.setExchangeLeaveHours(dateUtil.getFloatWithOneBit(exchangeLeaveHours));
                                                    dailyReport.setOthersLeaveHours(dateUtil.getFloatWithOneBit(othersLeaveHours));

                                                    dailyReport.setDailyOvertimeHours(dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));

                                                    dailyReport.setLateCount(lateCount);
                                                    dailyReport.setLeaveEarlyCount(leaveEarlyCount);
                                                    dailyReport.setAdditionClockCount(additionClockCount);
                                                    dailyReport.setNeglectWorkCount(neglectWorkCount);

                                                    dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));

                                                    dailyReport.setDayType("C");
                                                }else{ //如果这一天不在考勤组设置的工作日中，则这一天应该按照工作日全部记为加班，性质与特殊不打卡日一致
                                                    dailyReport.setAdditionClockCount(additionClockCount);
                                                    //dailyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(actualAttendanceHours));
                                                    dailyReport.setDailyOvertimeHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                                    dailyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(actualAttendanceHours) + dateUtil.getFloatWithOneBit(addAttendanceHours) + dateUtil.getFloatWithOneBit(frontExtAddAttendanceHours));
                                                    dailyReport.setDayType("B");
                                                }
                                            }
                                        }
                                    }
                                }
                                dailyReport.setGroupId(attendGroupID);
                                //将当前人员每一天的考勤计算结果存入集合
                                dailyReportMap.put(i, dailyReport);
//                                if(contactBasic.getContactId().equals("eba24a1534")){
//                                    if(i == 3){
//                                        System.out.println(JSON.toJSONString(dailyReport));
//                                    }
//                                }
                                //System.out.println(i);

                            }
                        }
                    }

                    //循环dailyReportMap，计算并生成月度统计报告对象 - 这一步需要计算跨2天以上的休假 - 需要计算和区分一个人的入职和离职日期（在开始循环时判断）
                    int joinDay = 0;
                    int leaveDay = 0;
                    if(null != joinedWorkingListMap.get(contactBasic.getContactId())){
                        joinDay = dateUtil.getDayByDate(joinedWorkingListMap.get(contactBasic.getContactId()).getOnboardActualDate());
                    }
                    if(null != leaveWorkingListMap.get(contactBasic.getContactId())){
                        leaveDay = dateUtil.getDayByDate(leaveWorkingListMap.get(contactBasic.getContactId()).getLeaveActualDate());
                    }

                    List<DingLeaveRecord> userDingLeaveRecords = leaveRecordsMap.get(contactBasic.getDingUserid());
                    List<FrontLineVacationRecord> userFrontLeaveRecords = frontLineVacationRecordsMap.get(contactBasic.getContactId());

                    //计算并获取跨天的请假，即这一天，全天都请假
                    Map<Integer, String> fullLeaveDayMap = attendanceUtil.getLeaveRangeDate(userDingLeaveRecords, userFrontLeaveRecords, firstDate, lastDate);

//                    if(contactBasic.getContactId().equals("eba24a1534")){
//                        System.out.println(JSON.toJSONString(userFrontLeaveRecords));
//                    }


                    //用于存储调整后的日统计数据（鉴别离职和入职日期、跨日休假的情况）
                    Map<Integer, AttendanceMonthlyReport> finalDailyReportMap = new HashMap<>();


                    //定义月报表变量
                    float monthlyShouldAttendanceHours = 0F; //月度应出勤
                    float monthlyActualAttendanceHours = 0F; //月度实际出勤
                    float monthlySpecialDayAttendanceHours = 0F; //月度特殊日出勤

                    float monthlyCasualLeaveHours = 0F; //月度事假
                    float monthlyMedicalLeaveHours = 0F; //月度病假
                    float monthlyAnnualLeaveHours = 0F; //月度年假
                    float monthlyMaternityLeaveHours = 0F; //月度产假
                    float monthlyMarriageLeaveHours = 0F; //月度婚假
                    float monthlyBereavementLeaveHours = 0F; //月度丧假
                    float monthlyExchangeLeaveHours = 0F; //月度调休
                    float monthlyOthersLeaveHours = 0F; //月度其它假

                    float monthlyDailyOvertimeHours = 0F; //月度日常加班
                    float monthlyWeekendOvertimeHours = 0F; //月度周末加班
                    float monthlyHolidayOvertimeHours = 0F; //月度节假日加班

                    int monthlyLateCount = 0; //月度迟到次数
                    int monthlyLeaveEarlyCount = 0; //月度早退次数
                    int monthlyAdditionClockCount = 0; //月度补卡次数
                    int monthlyNeglectWorkCount = 0; //月度旷工次数

                    float monthlyTotalHours = 0F; //月度总工时

                    String lastGroupID = ""; //定义用户最后一个考勤组ID

                    //循环计算dailyReportMap中存储的该员工在当月每天的考勤计算结果，得出月度结果
                    int totalDays = maxDays; //初始化每月最后一天考勤计算日
                    int startI = 1; //初始化每月第一天考勤计算日
                    if(joinDay != 0 && leaveDay == 0){ //本月入职，本月未离职，同时查询全天休假记录
                        startI = joinDay;
                    }else if(joinDay == 0 && leaveDay != 0){ //本月离职，同时查询全天休假记录
                        totalDays = leaveDay;
                    }else if(joinDay != 0 && leaveDay != 0){ //本月入职，本月离职，同时查询全天休假记录
                        startI = joinDay;
                        totalDays = leaveDay;
                    }//其它情况属于本月无入职和离职，同时查询全天休假记录
                    for (int i = startI; i <= totalDays; i++) {
                        AttendanceMonthlyReport report = dailyReportMap.get(i);
                        if(null != report){
                            String dayType = (report.getDayType() == null) ? "" : report.getDayType();
                            String groupID = report.getGroupId();
                            float shiftHours = shiftInfoMap.get(groupInfoMap.get(groupID).getAttendanceShiftId()).getAutoDayworkHours(); //考勤班次的应出勤时间
                            if(null != fullLeaveDayMap.get(i)){
                                if(dayType == "A" || dayType == "C"){
                                    String leaveCode = fullLeaveDayMap.get(i);
                                    DingVacationType dingVacationType = vacationTypeMap.get(leaveCode);
                                    report = new AttendanceMonthlyReport(0F);
                                    report.setDayType(dayType);
                                    report.setShouldAttendanceHours(dayType == "A" ? 0F : shiftHours);
                                    if(dingVacationType.getLeaveName().equals("事假")){
                                        report.setCasualLeaveHours(shiftHours);
                                    }
                                    else if(dingVacationType.getLeaveName().equals("病假")){
                                        report.setMedicalLeaveHours(shiftHours);
                                    }
                                    else if(dingVacationType.getLeaveName().equals("年假")){
                                        report.setAnnualLeaveHours(shiftHours);
                                    }
                                    else if(dingVacationType.getLeaveName().equals("产假")){
                                        report.setMaternityLeaveHours(shiftHours);
                                    }
                                    else if(dingVacationType.getLeaveName().equals("婚假")){
                                        report.setMarriageLeaveHours(shiftHours);
                                    }
                                    else if(dingVacationType.getLeaveName().equals("丧假")){
                                        report.setBereavementLeaveHours(shiftHours);
                                    }
                                    else if(dingVacationType.getLeaveName().equals("调休")){
                                        report.setExchangeLeaveHours(shiftHours);
                                    }
                                    else {
                                        report.setOthersLeaveHours(shiftHours);
                                    }
                                }
                            }
                            report.setContactId(contactBasic.getContactId());
                            finalDailyReportMap.put(i, report);

                            monthlyShouldAttendanceHours = monthlyShouldAttendanceHours + report.getShouldAttendanceHours();
                            monthlyActualAttendanceHours = monthlyActualAttendanceHours + report.getActualAttendanceHours();
                            monthlySpecialDayAttendanceHours = monthlySpecialDayAttendanceHours + report.getSpecialDayAttendanceHours();

                            monthlyCasualLeaveHours = monthlyCasualLeaveHours + report.getCasualLeaveHours();
                            monthlyMedicalLeaveHours = monthlyMedicalLeaveHours + report.getMedicalLeaveHours();
                            monthlyAnnualLeaveHours = monthlyAnnualLeaveHours + report.getAnnualLeaveHours();
                            monthlyMaternityLeaveHours = monthlyMaternityLeaveHours + report.getMaternityLeaveHours();
                            monthlyMarriageLeaveHours = monthlyMarriageLeaveHours + report.getMarriageLeaveHours();
                            monthlyBereavementLeaveHours = monthlyBereavementLeaveHours + report.getBereavementLeaveHours();
                            monthlyExchangeLeaveHours = monthlyExchangeLeaveHours + report.getExchangeLeaveHours();
                            monthlyOthersLeaveHours = monthlyOthersLeaveHours + report.getOthersLeaveHours();

                            monthlyDailyOvertimeHours = monthlyDailyOvertimeHours + report.getDailyOvertimeHours();
                            monthlyWeekendOvertimeHours = monthlyWeekendOvertimeHours + report.getWeekendOvertimeHours();
                            monthlyHolidayOvertimeHours = monthlyHolidayOvertimeHours + report.getHolidayOvertimeHours();

                            monthlyLateCount = monthlyLateCount + report.getLateCount();
                            monthlyLeaveEarlyCount = monthlyLeaveEarlyCount + report.getLeaveEarlyCount();
                            monthlyAdditionClockCount = monthlyAdditionClockCount + report.getAdditionClockCount();
                            monthlyNeglectWorkCount = monthlyNeglectWorkCount + report.getNeglectWorkCount();

                            monthlyTotalHours = monthlyTotalHours + report.getTotalCountHours();
                            lastGroupID = report.getGroupId();
                        }
//                        if(contactBasic.getContactId().equals("eba24a1534")){
//                            if(i == 3){
//                                System.out.println(JSON.toJSONString(report));
//                            }
//                        }
                    }
                    //将每个人的每日报告记录以通讯录ID为Key，月度的每日报表集合为Value进行存储
                    totalDailyReportMaps.put(contactBasic.getContactId(), finalDailyReportMap);

                    //向月度报表添加数据
                    userMonthlyReport.setContactId(contactBasic.getContactId());
                    userMonthlyReport.setShouldAttendanceHours(dateUtil.getFloatWithOneBit(monthlyShouldAttendanceHours));
                    userMonthlyReport.setActualAttendanceHours(dateUtil.getFloatWithOneBit(monthlyActualAttendanceHours));

                    userMonthlyReport.setSpecialDayAttendanceHours(dateUtil.getFloatWithOneBit(monthlySpecialDayAttendanceHours));
                    userMonthlyReport.setCasualLeaveHours(dateUtil.getFloatWithOneBit(monthlyCasualLeaveHours));
                    userMonthlyReport.setMedicalLeaveHours(dateUtil.getFloatWithOneBit(monthlyMedicalLeaveHours));
                    userMonthlyReport.setAnnualLeaveHours(dateUtil.getFloatWithOneBit(monthlyAnnualLeaveHours));
                    userMonthlyReport.setMaternityLeaveHours(dateUtil.getFloatWithOneBit(monthlyMaternityLeaveHours));
                    userMonthlyReport.setMarriageLeaveHours(dateUtil.getFloatWithOneBit(monthlyMarriageLeaveHours));
                    userMonthlyReport.setBereavementLeaveHours(dateUtil.getFloatWithOneBit(monthlyBereavementLeaveHours));
                    userMonthlyReport.setExchangeLeaveHours(dateUtil.getFloatWithOneBit(monthlyExchangeLeaveHours));
                    userMonthlyReport.setOthersLeaveHours(dateUtil.getFloatWithOneBit(monthlyOthersLeaveHours));

                    userMonthlyReport.setDailyOvertimeHours(dateUtil.getFloatWithOneBit(monthlyDailyOvertimeHours));
                    userMonthlyReport.setWeekendOvertimeHours(dateUtil.getFloatWithOneBit(monthlyWeekendOvertimeHours));
                    userMonthlyReport.setHolidayOvertimeHours(dateUtil.getFloatWithOneBit(monthlyHolidayOvertimeHours));

                    userMonthlyReport.setLateCount(monthlyLateCount);
                    userMonthlyReport.setLeaveEarlyCount(monthlyLeaveEarlyCount);
                    userMonthlyReport.setAdditionClockCount(monthlyAdditionClockCount);
                    userMonthlyReport.setNeglectWorkCount(monthlyNeglectWorkCount);

                    userMonthlyReport.setTotalCountHours(dateUtil.getFloatWithOneBit(monthlyTotalHours));

                    userMonthlyReport.setGroupId(lastGroupID);

                }

                AttendanceGroupInfo noAttendsStaffGpInfo = groupInfoMap.get(groupStaffMap.get(contactBasic.getContactId()));
                if(null != noAttendsStaffGpInfo && noAttendsStaffGpInfo.getAttendanceType() == 4){
                    //这是默认全勤的考勤组

                    //获取考勤组中的特殊打卡日
                    String spIDs = noAttendsStaffGpInfo.getSpecialCheckIds();
                    int spDays = 0;
                    if(null != spIDs){
                        JSONArray jsonArray = JSONArray.parseArray(spIDs);
                        if(null != jsonArray){
                            for (Object id : jsonArray
                            ) {
                                SpecialCheckDate spd = specialCheckDateMap.get(id); //打卡标志，A为不打卡标志，表示该日期不需要打卡，B为打卡标志，表示该日期需要打卡
                                if(spd.getCheckFlag().equals("B")){
                                    spDays = spDays + 1;
                                }
                            }
                        }
                    }
                    float spHours = (float)spDays * 8;
                    userMonthlyReport.setContactId(contactBasic.getContactId());
                    userMonthlyReport.setShouldAttendanceHours(shouldAttendanceHours);
                    userMonthlyReport.setActualAttendanceHours(shouldAttendanceHours);
                    userMonthlyReport.setSpecialDayAttendanceHours(spHours);
                    userMonthlyReport.setTotalCountHours(shouldAttendanceHours + spHours);
                    userMonthlyReport.setFileMonth(month.toString());
                }
                AttendanceGroupInfo noAttendsDeptGpInfo = groupInfoMap.get(deptsMap.get(deptID));
                if(null == noAttendsDeptGpInfo && null == noAttendsStaffGpInfo){
                    //这是没有加入任何考勤组的人员
                    userMonthlyReport.setContactId(contactBasic.getContactId());
                    userMonthlyReport.setFileMonth(month.toString());
                }
                //将月度统计报告对象添加到结果集
                reportList.add(userMonthlyReport);
            }
            logUtil.insertSystemEventLog(staffName.toString(), currentDate, "计算了" + month + "月份的考勤报表", "考勤");
        }
        AttendanceUtil.reportList = reportList;
        resultMap.put("report", reportList);
        resultList.add(resultMap);
        resultList.add(totalDailyReportMaps);
        logger.info("计算完毕");
        resultEntity.setCode("S");
        resultEntity.setMsg("Success");
        resultEntity.setDataList(resultList);
        return resultEntity;
    }


    /**
     * 接收前端请求，对考勤月度报表进行归档
     * @param map 前端传入的请求归档的月份
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/basic/doFileAttendanceMonthlyReport")
    @ResponseBody
    public ResultEntity doFileAttendanceMonthlyReport(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Date date = new Date();
        Object staffName = request.getAttribute("staffName");

        if(null != map){
            Object month = map.get("month");
            if(null != month && null != AttendanceUtil.reportList && AttendanceUtil.reportList.size() != 0){
                List<AttendanceMonthlyReport> filedReports = iAttendanceMonthlyReportService.selectAttendanceMonthlyReportByArchiveMonth(month.toString());
                if(filedReports.size() != 0){
                    resultEntity.setCode("F");
                    resultEntity.setMsg("您指定月份的考勤已经归档");
                    return resultEntity;
                }
                List<AttendanceMonthlyReport> pendingList = AttendanceUtil.reportList;
                for (AttendanceMonthlyReport amr : pendingList
                     ) {
                    amr.setcTime(date);
                    amr.setFileMonth(month.toString());
                    iAttendanceMonthlyReportService.insertAttendanceMonthlyReport(amr);
                }
                AttendanceUtil.reportList = new ArrayList<>(); //将缓存月度报表集合初始化，以防止重复归档
                resultEntity.setCode("S");
                resultEntity.setMsg("Success");
                logUtil.insertSystemEventLog(staffName.toString(), date, "归档了" + month + "月份的考勤报表", "考勤");
                return resultEntity;
            }else {
                resultEntity.setCode("F");
                resultEntity.setMsg("请先计算您指定月份的考勤");
                return resultEntity;
            }
        }
        resultEntity.setCode("F");
        resultEntity.setMsg("归档失败");
        return resultEntity;
    }


    /**
     * 接收用户请求，进行解归档操作
     * @param map 请求解归档的月份
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/basic/doUnFileAttendanceMonthlyReport")
    @ResponseBody
    public ResultEntity doUnFileAttendanceMonthlyReport(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Date date = new Date();
        Object staffName = request.getAttribute("staffName");
        if(null != map){
            Object month = map.get("month");
            List<AttendanceMonthlyReport> reportList = iAttendanceMonthlyReportService.selectAttendanceMonthlyReportByArchiveMonth(month.toString());
            if(null == reportList || reportList.size() == 0){
                resultEntity.setCode("F");
                resultEntity.setMsg("该月份尚未归档，无需解归档");
                return resultEntity;
            }else {
                //查询是否被薪资计算引用
                List<SalaryMonthlyReport> salaryMonthlyReports = iSalaryMonthlyReportService.selectSalaryMonthlyReportByFileMonth(month.toString());
                if(null != salaryMonthlyReports && salaryMonthlyReports.size() != 0){
                    resultEntity.setCode("F");
                    resultEntity.setMsg("该月份已经被薪资计算模块使用，不能解归档");
                    return resultEntity;
                }else {
                    for (AttendanceMonthlyReport amr : reportList
                    ) {
                        iAttendanceMonthlyReportService.deleteAttendanceMonthlyReport(amr);
                    }
                    logUtil.insertSystemEventLog(staffName.toString(), date, "解归档了" + month + "月份的考勤报表", "考勤");
                    resultEntity.setCode("S");
                    resultEntity.setMsg("Success");
                    return resultEntity;
                }
            }
        }
        resultEntity.setCode("F");
        resultEntity.setMsg("解归档失败");
        return resultEntity;
    }


    /**
     * 接收前端的请求，查询指定月份的考勤报表归档数据
     * @param map 需要查询的归档月份
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/basic/getFiledAttendanceMonthlyReportList")
    @ResponseBody
    public ResultEntity getFiledAttendanceMonthlyReportList(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Date date = new Date();
        Object staffName = request.getAttribute("staffName");

        if(null != map){
            Object month = map.get("month");
            if(null != month){
                List<Map> resultList = new ArrayList<>();
                Map<String, List> resultMap = new HashMap<>();
                resultMap.put("contactList", iContactBasicService.selectAllContactBasic());
                resultMap.put("deptList", basicDeptInfoService.selectAllContactBasicDeptInfo());
                resultMap.put("monthlyReportList", iAttendanceMonthlyReportService.selectAttendanceMonthlyReportByArchiveMonth(month.toString()));
                resultList.add(resultMap);
                resultEntity.setCode("S");
                resultEntity.setMsg("Success");
                resultEntity.setDataList(resultList);
                logUtil.insertSystemEventLog(staffName.toString(), date, "查询了" + month + "月份的归档数据", "考勤");
                return resultEntity;
            }else {
                resultEntity.setCode("F");
                resultEntity.setMsg("参数不正确");
                return resultEntity;
            }
        }
        resultEntity.setCode("F");
        resultEntity.setMsg("查询失败");
        return resultEntity;
    }



}
